#include "concurrenceAlloc.h"
#include <algorithm>
#include <vector>
#include <thread>
#include <iostream>
#include <atomic>
#include <mutex>
using namespace std;

// 使用原子操作解决线程安全问题
std::atomic<size_t> malloc_costtime = 0;
std::atomic<size_t> free_costtime = 0;

// 统一的测试参数
const size_t ntimes = 100;    // 每轮次分配释放次数
const size_t nworks = 10;     // 线程数  
const size_t rounds = 50;     // 轮次

void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
    std::vector<std::thread> vthread(nworks);
    std::atomic<size_t> malloc_time = 0;
    std::atomic<size_t> free_time = 0;

    for (size_t k = 0; k < nworks; ++k)
    {
        vthread[k] = std::thread([&, k]() {
            std::vector<void*> v;
            v.reserve(ntimes);

            for (size_t j = 0; j < rounds; ++j)
            {
                size_t begin1 = clock();
                for (size_t i = 0; i < ntimes; i++)
                {
                    v.push_back(malloc(16));
                }
                size_t end1 = clock();

                size_t begin2 = clock();
                for (size_t i = 0; i < ntimes; i++)
                {
                    free(v[i]);
                }
                size_t end2 = clock();
                v.clear();

                malloc_time.fetch_add(end1 - begin1, std::memory_order_relaxed);
                free_time.fetch_add(end2 - begin2, std::memory_order_relaxed);
            }
        });
    }

    for (auto& t : vthread)
    {
        t.join();
    }

    printf("系统的malloc 函数的性能测试结果:\n");
    printf("%lu个线程并发执行%lu轮次，每轮次malloc %lu次: 花费：%lu ms\n",
           nworks, rounds, ntimes, malloc_time.load());

    printf("%lu个线程并发执行%lu轮次，每轮次free %lu次: 花费：%lu ms\n",
           nworks, rounds, ntimes, free_time.load());

    printf("%lu个线程并发malloc&free %lu次，总计花费：%lu ms\n",
           nworks, nworks * rounds * ntimes, malloc_time.load() + free_time.load());
}

void test()
{
    std::vector<void*> v;
    v.reserve(ntimes);

    for (size_t j = 0; j < rounds; ++j)
    {
        size_t begin1 = clock();
        for (size_t i = 0; i < ntimes; i++)
        {
            v.push_back(concurrentAlloc(16));
        }
        size_t end1 = clock();

        size_t begin2 = clock();
        for (size_t i = 0; i < ntimes; i++)
        {
            DeConcurrentAlloc(v[i], 16);
        }
        size_t end2 = clock();
        v.clear();

        malloc_costtime.fetch_add(end1 - begin1, std::memory_order_relaxed);
        free_costtime.fetch_add(end2 - begin2, std::memory_order_relaxed);
    }
    
    // 线程结束时清理自己的ThreadCache
    if (PTLSthreadCache != nullptr) {
        PTLSthreadCache->Destroy();
        delete PTLSthreadCache;
        PTLSthreadCache = nullptr;
    }
}

void BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
    std::vector<std::thread> vthread(nworks);

    // 重置计时器
    malloc_costtime = 0;
    free_costtime = 0;

    for (size_t k = 0; k < nworks; ++k)
    {
        vthread[k] = std::thread(test);
    }

    for (auto& t : vthread)
    {
        t.join();
    }

    printf("高并发内存池性能测试结果:\n");
    printf("%lu个线程并发执行%lu轮次，每轮次concurrent alloc %lu次: 花费：%lu ms\n",
           nworks, rounds, ntimes, malloc_costtime.load());

    printf("%lu个线程并发执行%lu轮次，每轮次concurrent dealloc %lu次: 花费：%lu ms\n",
           nworks, rounds, ntimes, free_costtime.load());

    printf("%lu个线程并发concurrent alloc&dealloc %lu次，总计花费：%lu ms\n",
           nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());

    // 清理PageCache
    PageCache::GetInst().release();
}

int main()
{
    cout << "==========================================================" << endl;
    
    // 使用相同的参数测试两种分配器
    size_t test_ntimes = 100;   // 每轮次操作次数
    size_t test_nworks = 100;    // 线程数
    size_t test_rounds = 100;    // 轮次
    
    // 测试内存池
    BenchmarkConcurrentMalloc(test_ntimes, test_nworks, test_rounds);
    cout << endl << endl;
    
    // 测试系统malloc
    BenchmarkMalloc(test_ntimes, test_nworks, test_rounds);
    
    cout << "==========================================================" << endl;

    return 0;
}